#include "gamescene.h"
#include "utility.h"
#include "player.h"
#include "battle.h"
#include <boost/bind.hpp>

bool CGameScene::Init(const char *mapName)
{
	if(mapName == NULL || m_pSprite != NULL || m_width != 0 || m_height != 0)
		return false;
	char buf[64];
	snprintf(buf,sizeof(buf),"map/%s.map",mapName);
	ulong len;
	uint8 *pData = CCFileUtils::sharedFileUtils()->getFileData(buf,"rb",&len);

	if(pData == NULL)
	{
		cout<<"read map file error"<<endl;
		return false;
	}

	CAutoDel<uint8> del(pData);
	if(len < 4)
		return false;
	memcpy(&m_tileW,pData,2);
	pData += 2;
	memcpy(&m_tileH,pData,2);
	pData += 2;

	if(len < (ulong)m_tileW*m_tileH/8+5)
		return false;
	size_t pos = 0;
	m_astar.Init(m_tileW,m_tileH,GetTileSize());
	for(size_t h = 0; h < m_tileH; h++)
	{
		for(size_t w = 0; w < m_tileW; w++)
		{
			if(pData[pos/8] & (1<<(pos%8)))
				SetCanWalk(false,w,h);
			else
				SetCanWalk(true,w,h);
			pos++;
		}
	}
	pData += m_tileW*m_tileH/8+1;
	size_t shelterLen = len - (m_tileW*m_tileH/8+1);
	if(shelterLen%2 != 0)
		return false;
	for(size_t i = 0; i < shelterLen; i += 2)
	{
		SPoint p;
		p.x = pData[i];
		p.y = pData[i+1];
		m_shelterList.push_back(p);
	}
	m_width = m_tileW*GetTileSize();
	m_height = m_tileH*GetTileSize();
	setContentSize(CCS(m_width,m_height));

	m_textureW = m_width/GetTextureSize();
	if(m_width%GetTextureSize() != 0)
		m_textureW++;
	m_textureH = m_height/GetTextureSize();
	if(m_height%GetTextureSize() != 0)
		m_textureH++;

	m_pSprite = new CCSprite **[m_textureW];//[m_mapWidth+1][m_mapHeight+1];  //2 dimensional array used to record 
	for(int i = 0; i < m_textureW; i++)
	{
		m_pSprite[i] = new CCSprite *[m_textureH];
		memset(m_pSprite[i],0,sizeof(CCTexture2D*)*m_textureH);
	}
	m_mapName = mapName;

	float eX,eY;
	do
	{
		uint16 x = Random(0,m_tileW);
		uint16 y = Random(0,m_tileH);
		if(m_astar.CanWalk(x,y))
		{
			x = x*GetTileSize()+GetTileSize()/2;
			y = y*GetTileSize()+GetTileSize()/2;
			SetPlayerPos(x,y);
			m_pMe = new CPlayer();
			m_pMe->SetLevel(4);
			m_pMe->Init();
			addChild(m_pMe,y);

			CCPoint p;
			p.x = x;
			p.y = y;
			eX = x;
			eY = y;
			SetMePos(p,true);
			break;
		}
	}
	while(1);

	m_pEnemy = new CPlayer();
	m_pEnemy->SetLevel(7);
	m_pEnemy->Init();
	//m_pEnemy->sortAllChildren();
	CCPoint p;
	p.x = eX+GetTileSize();//x;
	p.y = m_height-eY;//y;
	addChild(m_pEnemy,eY);
	m_pEnemy->setPosition(p);
	
	m_textBeginX = m_textEndX = m_textBeginY = m_textEndY = 0;
	//schedule(SEL_SCHEDULE(&CGameScene::UpdatePos),0.01f);
	//setScale(0.6);
	setTouchEnabled(true);
	return true;
}

CCPoint CGameScene::GetCanWalkPos()
{
	CCPoint pos;
	do
	{
		uint16 x = Random(0,m_tileW);
		uint16 y = Random(0,m_tileH);
		if(m_astar.CanWalk(x,y))
		{
			x = x*GetTileSize()+GetTileSize()/2;
			y = y*GetTileSize()+GetTileSize()/2;
			pos.x = x;
			pos.y = y;
			break;
		}
	}
	while(1);
	return pos;
}

CCPoint CGameScene::GetMePos()
{
	return m_mePos;
}
void CGameScene::SetMePos(CCPoint pos,bool update)
{
	m_mePos = pos;
	CCPoint p;
	p.x = m_mePos.x;
	p.y = m_height-m_mePos.y;
	if(update)
	{
		m_pMe->setPosition(p);
		reorderChild(m_pMe,(int)pos.y);
		sortAllChildren();
	}
	CCSize size = m_pMe->getContentSize();
	CCRect rect(pos.x-size.width,pos.y-size.height,size.width,size.height);
	for(size_t i = 0; i < m_shelterList.size(); i++)
	{
		p.x = m_shelterList[i].x*GetTileSize();
		p.y = m_shelterList[i].y*GetTileSize();
		if(InRect(p,rect))
		{
			m_pMe->setOpacity(165);
			return;
		}
	}
	m_pMe->setOpacity(255);
}
void CGameScene::UpdateScene(float dt)
{
	if(m_path.size() == 0)
		return;
	if(m_nextPathPos >= m_path.size())
	{
		if(m_pMe->GetState() == CPlayer::EPSRun)
		{
			m_pMe->SetState(CPlayer::EPSStand,m_pMe->GetDirect());
		}
		m_path.clear();
		m_nextPathPos = 0;
	}
	else
	{
		CCPoint targetPos;
		targetPos.x = m_path[m_nextPathPos].x;
		targetPos.y = m_path[m_nextPathPos].y;
		CCPoint playerPos = GetMePos();
		
		playerPos.x += m_xSpeed*dt;
		playerPos.y += m_ySpeed*dt;
		if(playerPos.x < 0)
			playerPos.x = 0;
		if(playerPos.x >= m_width)
			playerPos.x = m_width - 1;
		if(playerPos.y < 0)
			playerPos.y = 0;
		if(playerPos.y >= m_height)
			playerPos.y = m_height - 1;
		if((targetPos.x - playerPos.x)*m_xSpeed <= 0 && (targetPos.y - playerPos.y)*m_ySpeed <= 0)
		{
			playerPos.x = targetPos.x;//+m_xSpeed*dt;
			playerPos.y = targetPos.y;//+m_ySpeed*dt;
			SetMePos(playerPos,false);
			m_nextPathPos++;
			if(m_nextPathPos < m_path.size())
			{
				targetPos.x = m_path[m_nextPathPos].x;
				targetPos.y = m_path[m_nextPathPos].y;
				GetSpeed(playerPos,targetPos,m_xSpeed,m_ySpeed,m_curDirect);
				m_pMe->SetState(CPlayer::EPSRun,m_curDirect);
			}
		}
		else
		{
			SetMePos(playerPos,true);
			SetPlayerPos(playerPos.x,playerPos.y);
		}
	}
}

bool CGameScene::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent)
{
	CCPoint pos = pTouch->getPreviousLocationInView();//locationInView();	
	pos = convertTouchToNodeSpace(pTouch);
	pos.y = m_height-pos.y;

	CCPoint playerPos = m_pMe->getPosition();
	playerPos.y = m_height-playerPos.y;

	CCPoint enemyPos = m_pEnemy->getPosition();
	enemyPos.y = m_height-enemyPos.y;

	if(fabs(pos.x - enemyPos.x) <= GetTileSize() && fabs(pos.y - enemyPos.y) <= 3*GetTileSize())
	{
		CBattleScene *pScene = new CBattleScene();
		pScene->Init((CCScene*)this);
		return true;
	}
	if(m_astar.FindPath(playerPos.x,playerPos.y,pos.x,pos.y))
	{
		m_path = m_astar.GetPath();
		m_nextPathPos = 0;
		CCPoint src;
		src.x = playerPos.x;
		src.y = playerPos.y;
		CCPoint targetPos;
		targetPos.x = m_path[m_nextPathPos].x;
		targetPos.y = m_path[m_nextPathPos].y;
		GetSpeed(src,targetPos,m_xSpeed,m_ySpeed,m_curDirect);
		m_pMe->SetState(CPlayer::EPSRun,m_curDirect);
	}
	return true;
}

void CGameScene::UpdatePos(float dt)
{
	//double f = CCDirector::sharedDirector()->getSecondsPerFrame();
	double f = M_PI_4;
	static int x,y;
	static int xStep = 10;
	static int yStep = 0;
	x += xStep;
	y += yStep;
	if(x >= m_width)
	{
		y += m_screenSize.height;
		xStep = -10;
	}
	if(x <= 0)
	{
		y += m_screenSize.height;
		xStep = 10;
	}
	if(y >= m_height)
	{
		y = 0;
		x = 0;
	}
	SetPlayerPos(x,y);
}

void CGameScene::SetPlayerPos(uint16 x,uint16 y)
{
	SetVeiwPoint(x,y);
	LoadMapTexture();
}

void CGameScene::LoadMapTexture()
{
	uint16 textureX,textureY;
	textureX = m_viewPoint.x/GetTextureSize();
	if(textureX > 0 && (m_viewPoint.x%GetTextureSize() < GetTextureSize()/2))
		textureX--;
	textureY = m_viewPoint.y/GetTextureSize();
	if(textureY > 0 && (m_viewPoint.y%GetTextureSize() < GetTextureSize()/2))
		textureY--;

	uint16 endX,endY;
	endX = (m_viewPoint.x+m_screenSize.width)/GetTextureSize();
	if(endX < m_tileW && ((m_viewPoint.x+(int)m_screenSize.width)%GetTextureSize() > GetTextureSize()/2))
		endX += 2;
	else 
		endX ++;
	endY = (m_viewPoint.y+m_screenSize.width)/GetTextureSize();
	if(endY < m_tileH && ((m_viewPoint.y+(int)m_screenSize.height)%GetTextureSize() > GetTextureSize()/2))
		endY += 2;
	else
		endY ++;
	if(endX > m_textureW)
		endX = m_textureW;
	if(endY > m_textureH)
		endY = m_textureH;
	if(m_textBeginX == textureX && m_textEndX == endX && m_textBeginY == textureY && m_textEndY == endY)
		return;
	m_textBeginX = textureX;
	m_textEndX = endX;
	m_textBeginY = textureY;
	m_textEndY = endY;

	char buf[64];
	//for(uint16 y = textureY; y < endY; y++)
	for(uint16 y = 0; y < m_textureH; y++)
	{
		//for(uint16 x = textureX; x < endX; x++)
		for(uint16 x = 0; x < m_textureW; x++)
		{
			if(x >= textureX && x < endX && y >= textureY && y < endY)// && m_pSprite[x][y] == NULL)
			{
				snprintf(buf,sizeof(buf),"map/%s-%d.jpg",m_mapName.c_str(),y*m_textureW+x);
				AddImageToCache(buf,boost::bind(&CGameScene::AddMapTexture,this,_1,x,y));
				/*CCTexture2D *pT = AddImageToCache(buf);
				AddMapTexture(pT,x,y);*/
			}
			else if(m_pSprite[x][y] != NULL)
			{
				RemoveTexture(m_pSprite[x][y]->getTexture());
				removeChild(m_pSprite[x][y],true);
				m_pSprite[x][y] = NULL;
			}
		}
	}
}

void CGameScene::AddMapTexture(CCTexture2D *pText,uint16 x,uint16 y)
{
	if(pText == NULL || x >= m_textureW || y >= m_textureH)
		return;
	if(m_pSprite[x][y] != NULL)
		return;
	CCSprite *pSp = CCSprite::createWithTexture(pText);
	pSp->setScale(GetScale());
	m_pSprite[x][y] = pSp;
	pSp->setAnchorPoint(CCP(0,1));
	addChild(pSp,-1);
	CCPoint point;
	point.x = x*GetTextureSize();
	point.y = m_height-y*GetTextureSize();//textureY*GetTextureSize();
	pSp->setPosition(point);
}
void CGameScene::SetVeiwPoint(uint16 x,uint16 y)
{
	if((x > m_width*GetTileSize()) || (y > m_height*GetTileSize()) || (x < 0) || (y < 0))
		return;
	m_viewPoint.x = x - m_screenSize.width/2;
	m_viewPoint.y = y - m_screenSize.height/2;
	if(m_viewPoint.x < 0)
		m_viewPoint.x = 0;
	if(m_viewPoint.y < 0)
		m_viewPoint.y = 0;
	if(m_viewPoint.x > m_width-m_screenSize.width)
		m_viewPoint.x = m_width - m_screenSize.width;
	if(m_viewPoint.y > m_height - m_screenSize.height)
		m_viewPoint.y = m_height - m_screenSize.height;
	//setAnchorPoint(CCP(0,1));
	CCPoint p;
	p.x = -m_viewPoint.x;
	p.y = m_viewPoint.y+m_screenSize.height-m_height;
	setPosition(p);
}